package com.slipper.scheduled;

import java.util.concurrent.Future;

import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.NonNull;
import org.springframework.scheduling.quartz.QuartzJobBean;

import com.slipper.PaasContext;
import com.slipper.system.schedule.bo.ScheduleBO;
import com.slipper.system.schedule.bo.ScheduleLogBO;
import com.slipper.system.schedule.service.ScheduleLogService;
import com.slipper.core.thread.ThreadUtil;

/**
 * 定时任务
 */
public class ScheduledJob extends QuartzJobBean {
    public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    protected void executeInternal(@NonNull JobExecutionContext context) {
        ScheduleLogBO scheduleLogBO = null;
        ScheduleBO scheduleBO = null;
        long startTime = 0;
        ScheduleLogService scheduleLogService = PaasContext.getBean(ScheduleLogService.class);

        try {
            scheduleBO = (ScheduleBO) context.getMergedJobDataMap().get(JOB_PARAM_KEY);
    
            // 判断此任务是否已在执行，如果任务已执行记录执行日志并立即退出
            ScheduleLogBO qo = new ScheduleLogBO();
            qo.setTaskId(scheduleBO.getId());
            if (scheduleLogService.isRunning(qo)) {
                scheduleLogBO = new ScheduleLogBO();
                scheduleLogBO.setTaskId(scheduleBO.getId());
                scheduleLogBO.setType(scheduleBO.getType());
                scheduleLogBO.setTime(scheduleBO.getTime());
                scheduleLogBO.setExpression(scheduleBO.getExpression());
                scheduleLogBO.setBusinessType(scheduleBO.getBusinessType());
                scheduleLogBO.setBusinessId(scheduleBO.getBusinessId());
                scheduleLogBO.setParams(scheduleBO.getParams());
                scheduleLogBO.setStatus(ScheduleLogBO.STATUS_FAILURE);
                scheduleLogBO.setErrorMessage("任务已在执行！");
                scheduleLogBO.setStartTime(System.currentTimeMillis());
                scheduleLogBO.setEndTime(System.currentTimeMillis());
                scheduleLogBO.setTimeConsume(0L);
                scheduleLogBO.setCreateTime(System.currentTimeMillis());
                scheduleLogService.save(scheduleLogBO);
                
                return;
            }
            
            // 任务开始时间
            startTime = System.currentTimeMillis();
            
            // 数据库保存执行记录
            scheduleLogBO = new ScheduleLogBO();
            scheduleLogBO.setTaskId(scheduleBO.getId());
            scheduleLogBO.setType(scheduleBO.getType());
            scheduleLogBO.setTime(scheduleBO.getTime());
            scheduleLogBO.setExpression(scheduleBO.getExpression());
            scheduleLogBO.setBusinessType(scheduleBO.getBusinessType());
            scheduleLogBO.setBusinessId(scheduleBO.getBusinessId());
            scheduleLogBO.setParams(scheduleBO.getParams());
            scheduleLogBO.setStatus(ScheduleLogBO.STATUS_RUNNING);
            scheduleLogBO.setStartTime(System.currentTimeMillis());
            scheduleLogBO.setCreateTime(System.currentTimeMillis());
            scheduleLogService.save(scheduleLogBO);

            // 执行任务
            logger.info("任务准备执行，任务ID: {}, businessType: {}, businessId: {}, params: {}",
                    scheduleBO.getId(),
                    scheduleBO.getBusinessType(),
                    scheduleBO.getBusinessId(),
                    scheduleBO.getParams());
            Future<?> future = ThreadUtil.submit(RunnableFactory.createRunnable(scheduleBO));
            future.get();

            // 任务执行总时长
            long timeConsume = System.currentTimeMillis() - startTime;
            scheduleLogBO.setTimeConsume(timeConsume);
            scheduleLogBO.setStatus(ScheduleLogBO.STATUS_SUCCESS);
            scheduleLogBO.setEndTime(System.currentTimeMillis());
            scheduleLogService.save(scheduleLogBO);

            logger.info("任务执行完毕，任务ID: {}, businessType: {}, businessId: {}, params: {}, 总共耗时: {} 毫秒",
                    scheduleBO.getId(),
                    scheduleBO.getBusinessType(),
                    scheduleBO.getBusinessId(),
                    scheduleBO.getParams(),
                    timeConsume);
        } catch (Exception e) {
            logger.error("任务执行失败，任务ID: {}, businessType: {}, businessId: {}, params: {}",
                    scheduleBO == null ? "" : scheduleBO.getId(),
                    scheduleBO == null ? "" : scheduleBO.getBusinessType(),
                    scheduleBO == null ? "" : scheduleBO.getBusinessId(),
                    scheduleBO == null ? "" : scheduleBO.getParams(), e);

            if (scheduleLogBO != null) {
                // 任务执行总时长
                long timeConsume = System.currentTimeMillis() - startTime;
                scheduleLogBO.setTimeConsume(timeConsume);
                scheduleLogBO.setStatus(ScheduleLogBO.STATUS_FAILURE);
                scheduleLogBO.setEndTime(System.currentTimeMillis());
                if (e.toString().length() > 2000) {
                    scheduleLogBO.setErrorMessage(e.toString().substring(0, 2000));
                } else {
                    scheduleLogBO.setErrorMessage(e.toString());
                }
                scheduleLogService.save(scheduleLogBO);
            }
        }
    }
}
